/*
 * LoadPNG.cpp
 *
 *  Created on: Jul 12, 2009
 *      Author: kurt
 */

#include "Image.h"
#include "ImageUtil.h"
#include <GL/gl.h>
#include <png.h>
#include <csetjmp>
#include <cstdlib>
#include <malloc.h>
#include <cstring>
#include <iostream>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
#include "png++/png.hpp"
using namespace std;
using namespace objdraw;
using namespace boost::iostreams;

#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))

void ImageUtil_PNG_ReadFn(png_structp png_ptr, png_bytep data, png_size_t length)
{
	SDL_RWops * fp = (SDL_RWops *)png_get_io_ptr(png_ptr);
	SDL_RWread(fp, data,length,1);
}

bool ImageUtil::is_png(string file)
{
	SDL_RWops * fp = SDL_RWFromFile(file.c_str(),"rb");
	if(fp == NULL) 
		return false;
	bool ret = is_png(fp);
	SDL_RWclose(fp);
	return ret;
}
#define PNG_BYTES_TO_CHECK 8
bool ImageUtil::is_png(SDL_RWops * fp)
{
	if(fp == NULL) return false;
	
	unsigned char buf[PNG_BYTES_TO_CHECK];
	if(SDL_RWread(fp,buf,1,PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK)
		return false;
//	rewind back to original position
	SDL_RWseek(fp,-PNG_BYTES_TO_CHECK,SEEK_CUR);
	return png_check_sig(buf,PNG_BYTES_TO_CHECK);
}

Image * ImageUtil::loadImageFilePNG(string file, PixelFormat pixelFormat, DrawingCanvas * canvas)
{
	SDL_RWops * fp = SDL_RWFromFile(file.c_str(),"rb");
	Image * img = loadImageFilePNG(fp,pixelFormat,canvas);
	
	if(fp != NULL)
		SDL_RWclose(fp);
	return img;
}
Image * ImageUtil::loadImageFilePNG(SDL_RWops * fp, PixelFormat pixelFormat , DrawingCanvas * canvas)
{
	if(fp == NULL || !is_png(fp)) 
		return NULL;
	Image * rimg = new Image(canvas);
	
	Image::ImageData * data = &rimg->data;
	
	uint ploc = SDL_RWtell(fp);
	SDL_RWseek(fp,0,SEEK_END);
	uint size = SDL_RWtell(fp);
	char * fdata = (char *)malloc(size);
	SDL_RWseek(fp,ploc,SEEK_SET);
	SDL_RWread(fp,fdata,size,1);
	
	if(fdata == NULL)
	{
		rimg->Delete();
		return NULL;
	}
	
	//load image from buffer
//	stringstream data = stringstream(ios::binary | ios::in | ios::out);
//	strstream isbuff(fdata,size, ios::in | ios::out | ios::binary);
	stream<array> isbuff(fdata,size);
	
	png::image<png::rgba_pixel> img = png::image<png::rgba_pixel>(isbuff);
	
	free(fdata);
	fdata = NULL;
	
	size_t width, height, bpp;
	width = img.get_width();
	height = img.get_height();
	bpp = 32;
	
	size_t texWidth, texHeight;
	texWidth = IsPower2(width) ? width : getNextPower2(width);
	texHeight = IsPower2(height) ? height : getNextPower2(height);
	
	size_t buff_size = texWidth*texHeight*sizeof(uint32_t);
	uint32_t * pdata = (uint32_t *)malloc(buff_size);
	if(pdata == NULL)
	{
		rimg->Delete();
		return NULL;
	}
	memset(pdata,0,buff_size);
	
	for(uint32_t i = 0; i < height; i++)
	{
		for(uint32_t j = 0; j < width; j++)
		{
			union color_u
			{
				struct 
				{ 
					uint8_t r;
					uint8_t g;
					uint8_t b;
					uint8_t a; 
				};
				uint32_t c;
			};
			color_u color;
			color.r = img.get_pixel(j,i).red;
			color.g = img.get_pixel(j,i).green;
			color.b = img.get_pixel(j,i).blue;
			color.a = img.get_pixel(j,i).alpha;
			pdata[(i * texWidth) + j] = color.c;
		}
	}
	
	glGenTextures(1,&data->texid);
	glBindTexture(GL_TEXTURE_2D,data->texid);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 
				 texWidth, texHeight, 
				 0, GL_RGBA, 
				 GL_UNSIGNED_BYTE, pdata);
	
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
//	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
//	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
	
	//set image data properties
	data->bpp = bpp;
	data->height = height;
	data->width = width;
	data->textureHeight = texHeight;
	data->textureWidth = texWidth;
	data->data = (unsigned int *)pdata;
	data->size = buff_size;
	
	rimg->setStart(Location(0,0));
	rimg->setEnd(Location(data->width,data->height));
	
	return rimg;
}
